#include "common.h"

#define MC_MEMCACHED_END   (sizeof(mc_http_memcached_end) - 1)
static u_char  mc_http_memcached_end[] = CRLF "END" CRLF;

int MC_AddCommand(Upstream *up, int method, String *str)
{
    Conn *c = up->parent->conn;
    Memcache *mc;
    size_t len;
    Buf *buf;
    Chain *chain, *temp;
    
    if (up->data != NULL) {
        return HTTP_ERR;
    }
    up->data = DS_Pcalloc(c->pool, sizeof(Memcache));
    if (up->data == NULL) {
        Log_Write(g_server->log, "MC: No Memory");
    }
    mc = up->data;
    mc->method = method;
    mc->c = up->peer;
    mc->key.data = DS_Pcalloc(c->pool, str->len);
    memcpy(mc->key.data, str->data, str->len);
    mc->key.len = str->len;

    if (method != MC_GET_METHOD) {
        /* Now Only Support Get Method */
        return HTTP_ERR;
    }

    len = sizeof("get ") - 1 + str->len + sizeof(CRLF) - 1;

    buf = DS_CreateTempBuf(c->pool, len);
    if (buf == NULL) {
        return HTTP_ERR;
    }

    chain = DS_AllocChainLink(c->pool);
    if (chain == NULL) {
        return HTTP_ERR;
    }

    chain->buf = buf;
    chain->next = NULL;

    *buf->last++ = 'g'; 
    *buf->last++ = 'e'; 
    *buf->last++ = 't'; 
    *buf->last++ = ' ';

    memcpy(buf->last, str->data, str->len);
    buf->last += str->len;
    *buf->last++ = CR; 
    *buf->last++ = LF;

    if (up->request_buf == NULL) {
        up->request_buf = chain;
        return HTTP_OK;
    }

    temp = up->request_buf;
    while (temp->next) {
        temp = temp->next;
    }
    temp->next = chain; 
        
}

int MC_ParseResponse(Upstream *up)
{
    Memcache *mc = up->data;
    Conn *c = up->parent->conn;
    Buf *buf;
    u_char  *p, *len;
    String line;

    if (mc == NULL) {
        return HTTP_ERR;
    }
    if (up->response_buf == NULL) {
        return HTTP_ERR;
    }
    buf = up->response_buf->buf;
    if (buf->pos == buf->last) {
        return HTTP_AGAIN;
    }

    for (p = buf->pos; p < buf->last; p++) {
        if (*p == LF) {
            goto found;
        }
    }

    return HTTP_AGAIN;

found:

    line.len = p - buf->pos - 1;
    line.data = buf->pos;

    p = buf->pos;

    if (memcmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) {

        p += sizeof("VALUE ") - 1;
        if (memcmp(p, mc->key.data, mc->key.len) != 0) {
            Log_Write(g_server->log, "Key and Value not match");
            return HTTP_ERR;
        }

        p += mc->key.len;
        if (*p++ != ' ') {
            goto no_valid;
        }
        /* skip flags */
        while (*p) {
            if (*p++ == ' ') {
                goto length;
            }
        }
        goto no_valid;

    length:

        len = p;
        while (*p && *p++ != CR) { /* void */ }

        mc->value.len = DS_Atoof(len, p - len - 1);
        mc->value.data = DS_Pcalloc(c->pool, mc->value.len);
        if (mc->value.data == NULL) {
            return HTTP_ERR;
        }
	    p++;
        if (buf->last - p < mc->value.len) {
            return HTTP_AGAIN;
        }
        memcpy(mc->value.data, p, mc->value.len);
        return HTTP_OK;
    }

    if (memcmp(p, "END\x0d", 3) == 0) {
        //Log_Write(g_server->log, "Key %s not found in Memcache", mc->key.data);
        mc->value.len = 0;
        return HTTP_OK;
    }

no_valid:

    Log_Write(g_server->log, "memcached sent invalid response");
    return HTTP_ERR;
    
}